/*
 * 结合应用层来分析一下semaphore的原理
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/semaphore.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/of_device.h>
#include <linux/sched.h>

struct semaphore sema;

struct class *driver_test_class;
dev_t dev;
struct cdev *cdev;

/*
 * 要理解down、down_interruptible、down_killable、down_timeout
 * 需要明白TASK_INTERRUPTIBLE、TASK_KILLABLE、TASK_UNINTERRUPTIBLE的区别
*/
static int semaphore_open(struct inode * inode, struct file * filp)
{
    return 0;
}
static ssize_t semaphore_read(struct file *file, __user char *buf, size_t count, loff_t *offp)
{
    down(&sema);
    printk("%s: down 1\n", __func__);

    down(&sema);
    printk("%s: down 2\n", __func__);

    return 0;
}

ssize_t semaphore_write(struct file *pfile, const char __user *buf, size_t count, loff_t *offp)
{
    up(&sema);
    printk("%s: up\n", __func__);

    return 1;
}

const struct file_operations my_ops = {
    .open = semaphore_open,
    .read = semaphore_read,
    .write = semaphore_write,
};

static int __init semaphore_init(void)
{
    struct device *drv_device = NULL;

    printk("%s: MAX_SCHEDULE_TIMEOUT = %ld \n", __func__, MAX_SCHEDULE_TIMEOUT);

    driver_test_class = class_create(THIS_MODULE, "my_class");
    alloc_chrdev_region(&dev, 10, 1, "my_driver");
    cdev = cdev_alloc();
    cdev->owner = THIS_MODULE;
    cdev->ops = &my_ops;
    cdev_add(cdev, dev, 1);
    drv_device = device_create(driver_test_class, NULL, dev, NULL, "semaphore_app");

    sema_init(&sema, 1);

    return 0;
}


static void __exit semaphore_exit(void)
{
    printk("%s...\n", __func__);

    device_destroy(driver_test_class, dev);
    class_destroy(driver_test_class);

    cdev_del(cdev);
    unregister_chrdev_region(cdev->dev, 1);
}

module_init(semaphore_init);
module_exit(semaphore_exit);
MODULE_LICENSE("Dual BSD/GPL");
